using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.RepositoryFactory.SchemaDiscovery.ObjectModel.Base;

namespace Microsoft.Practices.RepositoryFactory.CodeGeneration.ObjectModel.DbTypesHelperStrategies
{
   public sealed class OdpDbTypesHelper : IDbTypesHelperStrategy
   {
      #region IDbTypesHelperStrategy Members

      public string GetGenericDBType(DatabaseType type)
      {
         switch (type)
         {
            case DatabaseType.BFile: return "OracleDbType.BFile"; // DbType does not support BFile
            case DatabaseType.BinaryDouble: return "OracleDbType.BinaryDouble";
            case DatabaseType.BinaryFloat: return "OracleDbType.BinaryFloat";
            case DatabaseType.Blob: return "OracleDbType.Blob"; // DbType does not support Blob
            case DatabaseType.Boolean: return "DbType.Boolean";
            case DatabaseType.Byte: return "DbType.Byte";
            case DatabaseType.Char: return "DbType.StringFixedLength";
            case DatabaseType.Clob: return "OracleDbType.Clob"; // DbType does not support Clob
            case DatabaseType.Cursor: return "OracleDbType.RefCursor"; // DbType does not support Cursor
            case DatabaseType.Date: return "DbType.DateTime";
            case DatabaseType.Float: return "DbType.Single";
            case DatabaseType.Int32: return "DbType.Int32";
            case DatabaseType.IntervalDayToSecond: return "DbType.TimeSpan";
            case DatabaseType.IntervalYearToMonth: return "DbType.Int64";
            case DatabaseType.Long: return "DbType.String";
            case DatabaseType.LongRaw: return "DbType.Binary";
            case DatabaseType.NChar: return "DbType.StringFixedLength";
            case DatabaseType.NClob: return "OracleDbType.NClob"; // DbType does not support NClob
            case DatabaseType.Number: return "DbType.Decimal";
            case DatabaseType.NVarChar: return "DbType.String";
            case DatabaseType.Raw: return "DbType.Binary";
            case DatabaseType.Real: return "DbType.Decimal";
            // For the next 3 entries, keep in mind that the Oracle native Timestamp types can have
            // much greater precision.  When working with the .NET DateTime type, precision drops
            // to one third of a millisecond.
            case DatabaseType.Timestamp: return "DbType.DateTime";
            case DatabaseType.TimestampLocal: return "DbType.DateTime";
            case DatabaseType.TimestampWithTz: return "DbType.DateTime";
            case DatabaseType.VarChar: return "DbType.String";
            case DatabaseType.Xml: return "DbType.String"; // Though not formally documented, I inferred from ODP
            // documentation that a string would be acceptable
            default: return "DbType.Object";
         }
      }

      public string GetReaderMethod(DatabaseType type)
      {
         switch (type)
         {
            case DatabaseType.BFile: return "GetBytes";
            case DatabaseType.BinaryDouble: return "GetDouble";
            case DatabaseType.BinaryFloat: return "GetFloat";
            case DatabaseType.Blob: return "GetBytes";
            case DatabaseType.Boolean: return "GetBoolean";
            case DatabaseType.Byte: return "GetByte";
            case DatabaseType.Char: return "GetString";
            case DatabaseType.Clob: return "GetString";
            case DatabaseType.Date: return "GetDateTime";
            case DatabaseType.Float: return "GetFloat";
            case DatabaseType.Int32: return "GetInt32";
            case DatabaseType.IntervalDayToSecond: return "GetTimeSpan";
            case DatabaseType.IntervalYearToMonth: return "GetInt64";
            case DatabaseType.Long: return "GetString";
            case DatabaseType.LongRaw: return "GetBytes";
            case DatabaseType.NChar: return "GetString";
            case DatabaseType.NClob: return "GetString";
            case DatabaseType.Number: return "GetDecimal"; // biggest possible size given NUMBER Oracle type (note
            // that overflow is still possible because using .NET type.
            case DatabaseType.NVarChar: return "GetString";
            case DatabaseType.Raw: return "GetBytes";
            case DatabaseType.Real: return "GetDecimal";
            case DatabaseType.Timestamp: return "GetDateTime";
            case DatabaseType.TimestampLocal: return "GetDateTime";
            case DatabaseType.TimestampWithTz: return "GetDateTime";
            case DatabaseType.VarChar: return "GetString";
            case DatabaseType.Xml: return "GetString";
            default: return "//TODO No accessor found in OdpDbTypesHelper.GetReaderMethod(DatabaseType type)\n";
         }
      }

      public string GetClsType(DatabaseType type)
      {
         switch (type)
         {
            case DatabaseType.BFile: return "Byte[]";
            case DatabaseType.BinaryDouble: return "Double";
            case DatabaseType.BinaryFloat: return "Single";
            case DatabaseType.Blob: return "Byte[]";
            case DatabaseType.Boolean: return "Boolean";
            case DatabaseType.Byte: return "Byte";
            case DatabaseType.Char: return "String";
            case DatabaseType.Clob: return "String";
            case DatabaseType.Date: return "DateTime";
            case DatabaseType.Decimal: return "Decimal";
            case DatabaseType.Double: return "Double";
            case DatabaseType.Float: return "Double";
            case DatabaseType.Guid: return "Guid";
            case DatabaseType.IntervalDayToSecond: return "TimeSpan";
            case DatabaseType.IntervalYearToMonth: return "TimeSpan";
            case DatabaseType.Int64: return "Int64";
            case DatabaseType.Int32: return "Int32";
            case DatabaseType.Int16: return "Int16";
            case DatabaseType.NChar: return "String";
            case DatabaseType.NClob: return "String";
            case DatabaseType.Number: return "Decimal";
            case DatabaseType.NVarChar: return "String";
            case DatabaseType.Raw: return "Byte[]";
            case DatabaseType.Real: return "Decimal";
            case DatabaseType.Timestamp: return "DateTime";
            case DatabaseType.TimestampLocal: return "DateTime";
            case DatabaseType.TimestampWithTz: return "DateTime";
            case DatabaseType.VarChar: return "String";
            case DatabaseType.Xml: return "String";
            default: return "Object";
         }
      }

      public string GetProviderType(DatabaseType type)
      {
         switch (type)
         {
            case DatabaseType.BFile: return "OracleDbType.BFile";
            case DatabaseType.BinaryDouble: return "OracleDbType.BinaryDouble";
            case DatabaseType.BinaryFloat: return "OracleDbType.BinaryFloat";
            case DatabaseType.Blob: return "OracleDbType.Blob";
            case DatabaseType.Boolean: return "";
            case DatabaseType.Byte: return "OracleDbType.Byte";
            case DatabaseType.Char: return "OracleDbType.Char";
            case DatabaseType.Clob: return "OracleDbType.Clob"; 
            case DatabaseType.Cursor: return "OracleDbType.RefCursor";
            case DatabaseType.Date: return "OracleDbType.Date";
            case DatabaseType.Float: return "OracleDbType.Single";
            case DatabaseType.Int32: return "OracleDbType.Int32";
            case DatabaseType.IntervalDayToSecond: return "OracleDbType.IntervalDS";
            case DatabaseType.IntervalYearToMonth: return "OracleDbType.IntervalYM";
            case DatabaseType.Long: return "OracleDbType.Long";
            case DatabaseType.LongRaw: return "OracleDbType.LongRaw";
            case DatabaseType.NChar: return "OracleDbType.NChar";
            case DatabaseType.NClob: return "OracleDbType.NClob";
            case DatabaseType.Number: return "OracleDbType.Decimal";
            case DatabaseType.NVarChar: return "OracleDbType.NVarchar2";
            case DatabaseType.Raw: return "OracleDbType.Raw";
            case DatabaseType.Real: return "OracleDbType.Decimal";
            case DatabaseType.Timestamp: return "OracleDbType.Timestamp";
            case DatabaseType.TimestampLocal: return "OracleDbType.TimestampLZ";
            case DatabaseType.TimestampWithTz: return "OracleDbType.TimestampLTZ";
            case DatabaseType.VarChar: return "OracleDbType.Varchar2";
            case DatabaseType.Xml: return "OracleDbType.XmlType";
            default: return "OracleDbType.Varchar2";
         }
      }

      #endregion
   }
}
